{
    "cells": [
        {
            "cell_type": "markdown",
            "id": "ebbc68e6-181b-4585-8bb9-ed1566a908d9",
            "metadata": {},
            "source": [
                "# K-Means Clustering Algorithm"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "1320e3b1-bfb1-4651-af41-817a8e54ea9b",
            "metadata": {},
            "source": [
                "## Learning Outcomes\n",
                "This example teaches how to implement k-means clustering algorithm using NumPy and is based on the k-means example in cuPyNumeric. \n",
                "\n",
                "In this example, you will learn:\n",
                "* how to compute pairwise distances using `newaxis`\n",
                "* how to \"bin\" data using the `bincount` \n",
                "* how to locate data using `where` and `argmin`\n",
                "* how to use boolean mask to select data\n",
                "* how to compute `norm` of an n-dimensional array\n",
                "* how to determine if two NumPy arrays don't have the same values using `not_equal`.\n",
                "* how to plot clusters using matplotlib"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "a920ce4b-8d09-4d2c-b926-b1ddfcac5421",
            "metadata": {},
            "source": [
                "## Background\n",
                "To learn more about the clustering algorithm, see [this](https://stanford.edu/~cpiech/cs221/handouts/kmeans.html) material."
            ]
        },
        {
            "cell_type": "markdown",
            "id": "a72314cb-47be-40d3-90ac-5840f51f554d",
            "metadata": {},
            "source": [
                "## Implementation"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 1,
            "id": "9856192e-1a50-46a1-851e-e9c1b182e2e1",
            "metadata": {},
            "outputs": [],
            "source": [
                "import numpy as np\n",
                "from matplotlib import pyplot as plt\n",
                "from typing import Tuple"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "0b0c718b-0dde-43e6-b3e8-a78e5f76877d",
            "metadata": {},
            "source": [
                "For reproducibility, use a seed to generate a default random number generator "
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 2,
            "id": "3b5fd258-c696-4a07-89e9-6fda2b1b4c7d",
            "metadata": {},
            "outputs": [],
            "source": [
                "# seed the random number generator for deterministic runs\n",
                "random_seed: int = 42\n",
                "rng = np.random.default_rng(random_seed)"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 3,
            "id": "f118665b-1f77-40c3-8cf1-e1b48ec920e5",
            "metadata": {},
            "outputs": [],
            "source": [
                "def initialize(\n",
                "    n_elements: int, n_dims: int, n_centroids: int\n",
                ") -> Tuple[np.ndarray, np.ndarray]:\n",
                "    \"\"\"\n",
                "    Randomly initalize data and centroids of the clusters.\n",
                "\n",
                "    n_elements: int\n",
                "        Number of elements/observations that need to be clusters\n",
                "    n_dims: int\n",
                "        Dimension of the elements/observations\n",
                "    n_centroids: int\n",
                "        Number of clusters\n",
                "\n",
                "    Returns:\n",
                "        A Tuple with observations and centroids\n",
                "    \"\"\"\n",
                "    data = rng.random((n_elements, n_dims))\n",
                "    centroids = rng.random((n_centroids, n_dims))\n",
                "    return data, centroids"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 4,
            "id": "58705e8e-dc70-4039-a820-b8e596b8b05b",
            "metadata": {},
            "outputs": [],
            "source": [
                "def calculate_distances(\n",
                "    data: np.ndarray, centroids: np.ndarray, data_magnitude_squared: np.ndarray\n",
                ") -> np.ndarray:\n",
                "    \"\"\"\n",
                "    Return pairwise distance between the data and centroids.\n",
                "\n",
                "    data: np.ndarray\n",
                "        Observations that need to be clustered\n",
                "    centroids: np.ndarray\n",
                "        The center of the clusters\n",
                "    data_magnitude_squared: np.ndarray\n",
                "        Square of magnitude of observations (|y|^2)\n",
                "\n",
                "    Returns: np.ndarray\n",
                "\n",
                "    \"\"\"\n",
                "    centroid_dots = np.square(np.linalg.norm(centroids, ord=2, axis=1))\n",
                "    pairwise_distances = (\n",
                "        data_magnitude_squared[:, np.newaxis] + centroid_dots[np.newaxis, :]\n",
                "    )\n",
                "    # ||x-y||^2 = ||x||^2 + ||y||^2 - 2 x . y\n",
                "    # pairwise_distances has ||x||^2 + ||y||^2, so beta = 1\n",
                "    # The gemm calculates x.y for all x and y, so alpha = -2.0\n",
                "    pairwise_distances -= 2.0 * np.dot(data, centroids.T)\n",
                "    return pairwise_distances"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 5,
            "id": "670efdea-fffa-4835-83bf-04c8dbc544ee",
            "metadata": {},
            "outputs": [],
            "source": [
                "def relabel(pairwise_distances: np.ndarray) -> np.ndarray:\n",
                "    return np.argmin(pairwise_distances, axis=1)"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 6,
            "id": "cc81dad6-7661-449e-adaf-58c35698dfc3",
            "metadata": {},
            "outputs": [],
            "source": [
                "def find_centroids(\n",
                "    centroids: np.ndarray,\n",
                "    data: np.ndarray,\n",
                "    labels: np.ndarray,\n",
                "    pairwise_distances: np.ndarray,\n",
                "    zero_point: np.ndarray,\n",
                "    n_centroids: int,\n",
                ") -> np.ndarray:\n",
                "    \"\"\"Find centroids following the algorithm in the reference mentioned earlier\n",
                "    centroids: np.ndarray\n",
                "        The center of the clusters\n",
                "    data: np.ndarray\n",
                "        Observations that need to be clustered\n",
                "    labels: np.ndarray\n",
                "        The clusters the data belong to\n",
                "    pairwise_distances: np.ndarray\n",
                "        Pairwise distance between each data point and centroid\n",
                "    zero_point: np.ndarray\n",
                "\n",
                "    n_centroids: np.ndarray\n",
                "        Number of clusters\n",
                "    \"\"\"\n",
                "    # Get the number of points associated with each centroid\n",
                "    counts = np.bincount(labels, minlength=n_centroids)\n",
                "    # Build label masks for each centroid and sum across all the\n",
                "    # points assocated with each new centroid\n",
                "    distance_sum = 0.0\n",
                "    for idx in range(n_centroids):\n",
                "        # Boolean mask indicating where the points are for this center\n",
                "        centroid_mask = labels == idx\n",
                "        centroids[idx, :] = np.sum(\n",
                "            np.where(centroid_mask[..., np.newaxis], data, zero_point), axis=0\n",
                "        )\n",
                "        distance_sum += np.sum(\n",
                "            np.where(centroid_mask, pairwise_distances[:, idx], 0.0)\n",
                "        )\n",
                "    # To avoid introducing divide by zero errors\n",
                "    # If a centroid has no weight, we'll do no normalization\n",
                "    # This will keep its coordinates defined.\n",
                "    counts = np.maximum(counts, np.ones((1,), dtype=np.uint64))\n",
                "    centroids /= counts[:, np.newaxis]\n",
                "    return distance_sum"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 7,
            "id": "4fde3328-4b8a-454d-8a43-82fdfb51d1e4",
            "metadata": {},
            "outputs": [],
            "source": [
                "def run_kmeans(\n",
                "    n_centroids: int,\n",
                "    n_dims: int,\n",
                "    n_iters: int,\n",
                "    n_elements: int,\n",
                "    n_iter_check: int,\n",
                ") -> Tuple[np.ndarray, np.ndarray, np.ndarray]:\n",
                "    \"\"\"\n",
                "    Generate observations and cluster them into requested number of clusters.\n",
                "    n_centroids: int\n",
                "        Number of clusters\n",
                "    n_dims: int\n",
                "        Dimension of the elements/observations\n",
                "    n_iters: int\n",
                "        Maximum number of iterations\n",
                "    n_elements: int\n",
                "        Number of elements/observations that need to be clusters\n",
                "    n_iter_check: int\n",
                "        Determines how often we check for convergence.\n",
                "    \"\"\"\n",
                "    print(\"Running kmeans...\")\n",
                "    print(\"Number of data points: \" + str(n_elements))\n",
                "    print(\"Number of dimensions: \" + str(n_dims))\n",
                "    print(\"Number of centroids: \" + str(n_centroids))\n",
                "    print(\"Max iterations: \" + str(n_iters))\n",
                "\n",
                "    data, centroids = initialize(n_elements, n_dims, n_centroids)\n",
                "\n",
                "    data_magnitude_squared = np.square(np.linalg.norm(data, ord=2, axis=1))\n",
                "    zero_point = np.zeros((1, data.shape[1]), dtype=data.dtype)\n",
                "\n",
                "    labels = None\n",
                "    iteration = 0\n",
                "    prior_distance_sum = None\n",
                "    # We run for max iterations or until we converge\n",
                "    # We only test convergence every n_iter_check iterations\n",
                "    while iteration < n_iters:\n",
                "        pairwise_distances = calculate_distances(\n",
                "            data, centroids, data_magnitude_squared\n",
                "        )\n",
                "\n",
                "        new_labels = relabel(pairwise_distances)\n",
                "\n",
                "        distance_sum = find_centroids(\n",
                "            centroids,\n",
                "            data,\n",
                "            new_labels,\n",
                "            pairwise_distances,\n",
                "            zero_point,\n",
                "            n_centroids,\n",
                "        )\n",
                "\n",
                "        if iteration > 0 and iteration % n_iter_check == 0:\n",
                "            delta = distance_sum / prior_distance_sum\n",
                "            if delta > 1 - 0.000001:\n",
                "                break\n",
                "\n",
                "        prior_distance_sum = distance_sum\n",
                "        labels = new_labels\n",
                "        iteration += 1\n",
                "\n",
                "    return data, labels, centroids"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "70927fda-821b-4858-862d-cae5e6e6eedc",
            "metadata": {},
            "source": [
                "### Lets run the kmeans algorithm using a set of inputs"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 8,
            "id": "18ac6aab-48f3-4cce-8587-b0ec04600cba",
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "Running kmeans...\n",
                        "Number of data points: 256\n",
                        "Number of dimensions: 2\n",
                        "Number of centroids: 5\n",
                        "Max iterations: 100\n"
                    ]
                }
            ],
            "source": [
                "n_centroids: int = 5\n",
                "n_dims: int = 2\n",
                "n_elements: int = 256\n",
                "n_iter_check: int = 10\n",
                "n_iters: int = 100\n",
                "\n",
                "data, labels, centroids = run_kmeans(\n",
                "    n_centroids, n_dims, n_iters, n_elements, n_iter_check\n",
                ")"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "0f57c8bf-831e-427a-8bd4-143b71838e4a",
            "metadata": {},
            "source": [
                "Generate a color map to differentiate the clusters"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 9,
            "id": "01adc703-9a64-4985-9c86-3c5082f0d891",
            "metadata": {},
            "outputs": [],
            "source": [
                "label_color_map = {\n",
                "    0: \"blue\",\n",
                "    1: \"black\",\n",
                "    2: \"red\",\n",
                "    3: \"magenta\",\n",
                "    4: \"yellow\",\n",
                "    5: \"green\",\n",
                "    6: \"gray\",\n",
                "}\n",
                "\n",
                "# make sure we have unique color for each cluster (total number of clusters specified by n_centroids)\n",
                "assert len(label_color_map.items()) >= n_centroids"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "66864ad0-c462-4223-a249-f2539bbaf63c",
            "metadata": {},
            "source": [
                "Plot the clusters. Each color represents a cluster"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 10,
            "id": "5be8c360-d945-486a-9b0f-d0774287f4b9",
            "metadata": {},
            "outputs": [
                {
                    "data": {
                        "image/png": "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",
                        "text/plain": [
                            "<Figure size 640x480 with 1 Axes>"
                        ]
                    },
                    "metadata": {},
                    "output_type": "display_data"
                }
            ],
            "source": [
                "# lets plot the data colored by the cluster they belong to\n",
                "for label_value, label_color in label_color_map.items():\n",
                "    index = labels == label_value\n",
                "    plt.plot(data[index, 0], data[index, 1], \"o\", color=label_color)\n",
                "\n",
                "# lets plot the centroid of the clusters\n",
                "plt.scatter(\n",
                "    centroids[:, 0],\n",
                "    centroids[:, 1],\n",
                "    s=320,\n",
                "    marker=\"*\",\n",
                "    c=list(label_color_map.values())[0:n_centroids],\n",
                "    edgecolors=\"gray\",\n",
                ")\n",
                "plt.show()"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "f19e27d2-7f24-41da-962a-6a3ea61e53af",
            "metadata": {},
            "source": [
                "#### Exercise: Change the number of clusters and number of observations and see how the clusters change"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "id": "2b89556c-7e5d-4965-87ae-f3a653d9d3f7",
            "metadata": {},
            "outputs": [],
            "source": []
        }
    ],
    "metadata": {
        "kernelspec": {
            "display_name": "python3 (legate) *",
            "language": "python",
            "name": "conda-env-legate-py"
        },
        "language_info": {
            "codemirror_mode": {
                "name": "ipython",
                "version": 3
            },
            "file_extension": ".py",
            "mimetype": "text/x-python",
            "name": "python",
            "nbconvert_exporter": "python",
            "pygments_lexer": "ipython3",
            "version": "3.10.13"
        }
    },
    "nbformat": 4,
    "nbformat_minor": 5
}
